package com.example.thumbsupdemo

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.*
import android.util.Log
import android.view.View
import android.view.animation.Animation
import android.view.animation.AnticipateOvershootInterpolator
import android.view.animation.DecelerateInterpolator
import android.view.animation.OvershootInterpolator

/**
 * 拇指部分
 * 普通的拇指，就一张图片
 * 点击后，有一个小圈不断放大，里面的彩色拇指也跟随放大，最后拇指固定大小，并改变角度，圈继续放大最终消失
 *
 * 对图片进行几何变化，放大，缩小，旋转，透明
 *
 * 无需理会父布局的padding，它只会缩小本view，只要按照比例而非实际数值即可适应影响
 * getLeft是已经包含padding了的，不设置padding时，left = 0，padding = 10dp时，left = 30(不一定，但是大于0)
 * 所以width 和 height也是已经适配过padding了，拿适配过padding的数据计算得到的数据肯定也是适配了padding的
 *
 * 一张图似乎不能多次旋转，而是一张图多次作为基础旋转得到一张新的图
 * A -> B -> C xxx
 * A -> B A -> C A -> D √√√
 *
 * 还需要点赞取消
 */
class ThumbView(context: Context) : View(context) {
    private val mPaint = Paint()
    private var mChecked = false
    private var mUnCheckedBitmap =
        BitmapFactory.decodeResource(resources, R.mipmap.ic_thumbs_up_unchecked)
    private var mCheckedBitmap =
        BitmapFactory.decodeResource(resources, R.mipmap.ic_thumbs_up_checked)

    private var mThumbBitmap: Bitmap = mUnCheckedBitmap

    private var mRectF: RectF = RectF()

    private val mRASMin = RotateAndScaleEvaluator.RotateAndScale(ROTATE_NORMAL, SCALE_MIN)
    private val mRASMax = RotateAndScaleEvaluator.RotateAndScale(ROTATE_MAX, SCALE_MAX)
    private val mRASNormal = RotateAndScaleEvaluator.RotateAndScale(ROTATE_NORMAL, SCALE_NORMAL)

    // 点赞的动画
    private val mCheckedAnimationSet = AnimatorSet()
    private val mUncheckedAnimation: ObjectAnimator

    init {
        // 抗锯齿
        mPaint.isAntiAlias = true
        // 描边
        mPaint.style = Paint.Style.STROKE

        // 取消点赞的动画
        mUncheckedAnimation = ObjectAnimator.ofFloat(
            this,
            "uncheckedThumbScale",
            SCALE_NORMAL,
            SCALE_MAX,
            SCALE_NORMAL
        )
        mUncheckedAnimation.duration = DURATION_SCALE * 2
        // 随便弄一个，有空写一个好看的
        mUncheckedAnimation.interpolator = OvershootInterpolator()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        Log.d(TAG, "onMeasure")
        // 将图片缩放成合适大小
        val length = measuredHeight.coerceAtMost(measuredWidth)
        setMeasuredDimension(length, length)
        mUnCheckedBitmap = scaleBitmap(mUnCheckedBitmap, length, length)
        mCheckedBitmap = scaleBitmap(mCheckedBitmap, length, length)
        mThumbBitmap = mUnCheckedBitmap
    }

    /**
     * 缩放图片
     */
    private fun scaleBitmap(src: Bitmap, width: Int, height: Int): Bitmap {
        val w = src.width.toFloat()
        val h = src.height.toFloat()
        val scaleW = width / w
        val scaleH = height / h
        val scaleMatrix = Matrix()
        scaleMatrix.setScale(scaleW, scaleH)
        return Bitmap.createBitmap(src, 0, 0, w.toInt(), h.toInt(), scaleMatrix, true)
    }

    /**
     * 相当于左右各减去x倍
     */
    private fun setUncheckedThumbScale(arg: Float) {
        val x = (1 - arg) / 2
        val scaleLeft = width * x
        val scaleTop = height * x
        val scaleRight = width * (1 - x)
        val scaleBottom = height * (1 - x)
        mRectF.set(scaleLeft, scaleTop, scaleRight, scaleBottom)
        mThumbBitmap = mUnCheckedBitmap
        postInvalidate()
    }

    /**
     * 需要同时计算角度和缩放
     */
    fun setCheckedThumbScale(arg: RotateAndScaleEvaluator.RotateAndScale) {
        // 计算缩放
        val x = (1 - arg.scale) / 2
        val scaleLeft = width * x
        val scaleTop = height * x
        val scaleRight = width * (1 - x)
        val scaleBottom = height * (1 - x)
        mRectF.set(scaleLeft, scaleTop, scaleRight, scaleBottom)

        //计算角度
        val rotate = Matrix()
        rotate.setRotate(arg.rotate, (width / 2).toFloat(), (height / 2).toFloat())
        mThumbBitmap = Bitmap.createBitmap(
            mCheckedBitmap,
            0,
            0,
            mCheckedBitmap.width,
            mCheckedBitmap.height,
            rotate,
            true
        )

        postInvalidate()
    }

    /**
     * 手指按下，开始动画
     * 缩放并没有改变图的大小，而是图的显示范围rect
     * 1.缩小原图
     * 2.放大彩图，同时旋转
     * 3.缩小彩图，同时旋转回来
     *
     * 快速点击的时候，前一段得取消
     */
    fun onClick(checked: Boolean) {
        Log.d(TAG, "onClick: checked = $checked")
        mChecked = checked
        mCheckedAnimationSet.cancel()
        mUncheckedAnimation.cancel()
        if (checked) {
            // 1
            val unCheckedScaleToMin = ObjectAnimator.ofFloat(
                this,
                "uncheckedThumbScale",
                SCALE_NORMAL,
                SCALE_MIN
            )
            unCheckedScaleToMin.duration = DURATION_SCALE

            // 2
            val checkedScaleToMax = ObjectAnimator.ofObject(
                this,
                "checkedThumbScale",
                RotateAndScaleEvaluator(),
                mRASMin,
                mRASMax
            )
            checkedScaleToMax.duration = DURATION_SCALE

            // 3
            val checkedScaleToNormal = ObjectAnimator.ofObject(
                this,
                "checkedThumbScale",
                RotateAndScaleEvaluator(),
                mRASMax,
                mRASNormal
            )
            // 不同的插值器表现效果不同，OvershootInterpolator比默认的稍微生动点,也可以自己实现
            checkedScaleToNormal.interpolator = OvershootInterpolator()
            checkedScaleToNormal.duration = DURATION_RECOVER

            mCheckedAnimationSet.playSequentially(unCheckedScaleToMin, checkedScaleToMax, checkedScaleToNormal)
            mCheckedAnimationSet.start()
        } else {
            // 改变颜色，然后放大，缩小
            mThumbBitmap = mUnCheckedBitmap
            mUncheckedAnimation.start()
            postInvalidate()
        }
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        // 图片缩小了，绘制时要居中绘制，需要给定rect
        if (mRectF.isEmpty) {
            // 只有平常大小的0.8，因为有一个放大的效果，避免放大后显示不全
            Log.d(TAG, "onDraw: width = $width, height = $height")
            mRectF.left = width * 0.1F
            mRectF.top = height * 0.1F
            mRectF.right = width * 0.9F
            mRectF.bottom = height * 0.9F
        }
        canvas?.drawBitmap(mThumbBitmap, null, mRectF, mPaint)
    }

    companion object {
        private const val TAG = "ThumbView"

        private const val DURATION_SCALE = 200L
        private const val DURATION_RECOVER = 300L

        private const val SCALE_MIN = 0.2f
        private const val SCALE_NORMAL = 0.8f
        private const val SCALE_MAX = 1f

        private const val ROTATE_NORMAL = 0F
        private const val ROTATE_MAX = -30F
    }
}